home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / emulator / uae-0.000 / uae-0 / uae-0.6.0 / disk.c < prev    next >
C/C++ Source or Header  |  1996-05-04  |  11KB  |  474 lines

  1.  /* 
  2.   * UAE - The Un*x Amiga Emulator
  3.   * 
  4.   * Floppy disk emulation
  5.   *
  6.   * (c) 1995 Bernd Schmidt, Hannu Rummukainen
  7.   */
  8.  
  9. #include "sysconfig.h"
  10. #include "sysdeps.h"
  11.  
  12. #include "config.h"
  13. #include "options.h"
  14. #include "memory.h"
  15. #include "ersatz.h"
  16. #include "disk.h"
  17. #include "gui.h"
  18.  
  19. int indexpulse = 0;
  20.  
  21. UWORD* mfmwrite;
  22. static UWORD mfmwrbuffer[16384]; /* space for maximum disk DMA transfer */
  23.  
  24. static int side, direction, step;
  25. static UBYTE selected = 15;
  26. static int dskready;
  27. static int need_read = 0;
  28.  
  29. typedef struct {
  30.     UWORD sync;
  31.     UWORD len;
  32.     ULONG offs;
  33. } trackid;
  34.  
  35. typedef enum { ADF_NORMAL, ADF_EXT1 } drive_filetype;
  36. typedef struct {
  37.     FILE *diskfile;
  38.     drive_filetype filetype;
  39.     trackid trackdata[164];
  40.     unsigned int track;
  41.     int motoroff;
  42.     int wrprot;
  43.     unsigned int trackoffs,insecpos;
  44.     int secok;
  45.     UBYTE secbuf[544];
  46.     UWORD mfmbuf[544];
  47. } drive;
  48.  
  49. drive floppy[4];
  50.  
  51. static void drive_insert(drive *drv, int dnum, char *fname)
  52. {
  53.     unsigned char buffer[10];
  54.     
  55.     drv->diskfile = fopen(fname,"r+b");
  56.     if (drv->diskfile) {
  57.     drv->wrprot = 0;
  58.     } else {
  59.     drv->wrprot = 1;
  60.     drv->diskfile = fopen(fname, "rb");
  61.     if (!drv->diskfile) {
  62.         gui_filename(dnum, "");
  63.         return;
  64.     }
  65.     }
  66.     gui_filename(dnum, fname);
  67.     fread(buffer,sizeof(char),8,drv->diskfile);
  68.     if (strncmp((char *)buffer,"UAE--ADF",8) == 0) {    
  69.     int offs = 160*4+8;
  70.     int i;
  71.     
  72.         drv->filetype = ADF_EXT1;
  73.     drv->wrprot = 1; /* write to adf_ext1 not implemented */
  74.     for(i=0; i<160; i++) {
  75.         fread(buffer, 4, 1, drv->diskfile);
  76.         drv->trackdata[i].sync = buffer[0]*256 + buffer[1];
  77.         drv->trackdata[i].len = buffer[2]*256 + buffer[3];
  78.         drv->trackdata[i].offs = offs;
  79.         offs += drv->trackdata[i].len;
  80.     }
  81.     } else {
  82.     int i;
  83.         drv->filetype = ADF_NORMAL;
  84.     for(i=0; i<160; i++) {
  85.         drv->trackdata[i].len = 512 * 11;
  86.         drv->trackdata[i].sync = 0;
  87.         drv->trackdata[i].offs = i*512*11;
  88.     }
  89.     }
  90. }
  91.  
  92.  
  93. static void drive_step(drive *drv)
  94. {
  95.     if (direction) {
  96.     if (drv->track) drv->track--;
  97.     } else {
  98.     if (drv->track < 85) drv->track++;
  99.     }
  100. }
  101.  
  102.  
  103. static int drive_track0(drive *drv) 
  104. {
  105.     return drv->track == 0; 
  106. }
  107.  
  108. static int drive_writeprotected(drive *drv) 
  109. {
  110.     return drv->wrprot || drv->diskfile == NULL; 
  111. }
  112.  
  113. static int drive_empty(drive *drv)
  114. {
  115.     return drv->diskfile == 0; 
  116. }
  117.  
  118. static int drive_running(drive *drv)
  119. {
  120.     return !drv->motoroff; 
  121. }
  122.  
  123. static void drive_index(drive *drv)
  124. {
  125.     drv->trackoffs = 0;
  126.     drv->insecpos = 0;
  127. }
  128.  
  129. static void drive_motor(drive *drv, int off)
  130. {
  131.     if (drv->motoroff && !off) { 
  132.     drv->trackoffs = 0;
  133.     drv->insecpos = 0; 
  134.     drv->secok = 0; 
  135.     }
  136.     drv->motoroff = off;
  137. }
  138.  
  139. static ULONG drive_getmfmulong(drive *drv, unsigned int offs)
  140. {
  141.     return (drv->mfmbuf[offs] << 16) | drv->mfmbuf[offs+1];
  142. }
  143.  
  144. static ULONG drive_getseculong(drive *drv, unsigned int offs)
  145. {
  146.     return ((drv->secbuf[offs] << 24) | (drv->secbuf[offs+1] << 16) 
  147.         | (drv->secbuf[offs+2] << 8) | (drv->secbuf[offs+3]));
  148. }
  149.  
  150. static void drive_readsec(drive *drv)
  151. {
  152.     ULONG deven,dodd;
  153.     ULONG hck=0,dck=0;
  154.     int i;
  155.  
  156.     if (!drv->diskfile) return;
  157.     
  158.     drv->secbuf[0] = drv->secbuf[1] = 0x00;
  159.     drv->secbuf[2] = drv->secbuf[3] = 0xa1;
  160.     drv->secbuf[4] = 0xff;
  161.     drv->secbuf[5] = drv->track*2 + side;
  162.     drv->secbuf[6] = drv->trackoffs;
  163.     drv->secbuf[7] = 11-drv->trackoffs;
  164.     
  165.     for(i = 8; i < 24; i++)
  166.     drv->secbuf[i] = 0;
  167.     
  168.     fseek(drv->diskfile, 
  169.       drv->trackdata[drv->track*2 + side].offs + drv->trackoffs*512, 
  170.       SEEK_SET);
  171.     fread(&drv->secbuf[32],sizeof(UBYTE),512,drv->diskfile);
  172.     
  173.     drv->mfmbuf[0] = drv->mfmbuf[1] = 0xaaaa;
  174.     drv->mfmbuf[2] = drv->mfmbuf[3] = 0x4489;
  175.     
  176.     deven = drive_getseculong(drv, 4); dodd = deven >> 1;
  177.     deven &= 0x55555555; dodd &= 0x55555555;
  178.     
  179.     drv->mfmbuf[4] = dodd >> 16;
  180.     drv->mfmbuf[5] = dodd;
  181.     drv->mfmbuf[6] = deven>> 16; 
  182.     drv->mfmbuf[7] = deven;
  183.     
  184.     for (i = 8; i < 48; i++)
  185.     drv->mfmbuf[i] = 0;
  186.     for (i = 0; i < 512; i += 4){
  187.     deven = drive_getseculong(drv, i + 32);
  188.     dodd = deven >> 1;
  189.     deven &= 0x55555555; dodd &= 0x55555555;
  190.     drv->mfmbuf[(i>>1)+32] = dodd >> 16;
  191.     drv->mfmbuf[(i>>1)+33] = dodd;
  192.     drv->mfmbuf[(i>>1)+256+32] = deven>> 16;
  193.     drv->mfmbuf[(i>>1)+256+33] = deven;
  194.     }
  195.     
  196.     for(i = 4; i < 24; i += 2)
  197.     hck ^= drive_getmfmulong(drv, i);
  198.     
  199.     deven = dodd = hck; dodd >>= 1;
  200.     drv->mfmbuf[24] = dodd >> 16; drv->mfmbuf[25] = dodd;
  201.     drv->mfmbuf[26] = deven>> 16; drv->mfmbuf[27] = deven;
  202.     
  203.     for(i = 32; i < 544; i += 2)
  204.     dck ^= drive_getmfmulong(drv, i);
  205.     
  206.     deven = dodd = dck; dodd >>= 1;
  207.     drv->mfmbuf[28] = dodd >> 16; drv->mfmbuf[29] = dodd;
  208.     drv->mfmbuf[30] = deven>> 16; drv->mfmbuf[31] = deven;
  209.     
  210.     drv->secok = 1;
  211.     need_read = 0;
  212.     drv->insecpos = 0;
  213. }
  214.  
  215. static void drive_get_data(drive *drv, UWORD *mfm, UWORD *byt)
  216. {
  217.     if (drv->trackdata[drv->track*2 + side].sync == 0) {
  218.     /* Normal AmigaDOS format track */
  219.     if (!drv->secok || need_read)
  220.         drive_readsec(drv);
  221.     *mfm = drv->mfmbuf[drv->insecpos]; 
  222.     *byt = drv->secbuf[drv->insecpos++];
  223.     
  224.     if (drv->insecpos == 544){
  225.         drv->insecpos = 0;
  226.         drv->secok = 0;
  227.         if (++drv->trackoffs == 11)
  228.         drv->trackoffs = 0;
  229.     }
  230.     } else {
  231.     /* Raw MFM track */
  232.     if (drv->insecpos > drv->trackdata[drv->track*2+side].len) 
  233.         drv->insecpos = 0;
  234.     if (drv->insecpos == 0) {
  235.         *mfm = drv->trackdata[drv->track*2 + side].sync;
  236.     } else  {        
  237.         unsigned char data[2];
  238.         fseek(drv->diskfile, 
  239.           drv->insecpos*2 - 2 + drv->trackdata[drv->track*2+side].offs, 
  240.           SEEK_SET);
  241.         fread(data, 2, 1, drv->diskfile);
  242.         *mfm = data[0]*256 + data[1];
  243.         /* ??? how does this work? */
  244.         *byt = (data[0] & 0x55) | ((data[1] & 0x55)*2);
  245.     }
  246.     drv->insecpos++;
  247.     }
  248. }
  249.  
  250. #define MFMMASK 0x55555555
  251. static __inline__ ULONG getmfmlong(UWORD* mbuf) 
  252. {
  253.     return ((*mbuf << 16) | *(mbuf + 1)) & MFMMASK;
  254. }
  255.  
  256. static void drive_write_data(drive *drv, UWORD *mbuf, UWORD *mend)
  257. {
  258.     int i, secwritten = 0;
  259.     ULONG odd, even, chksum, id, dlong;
  260.     UBYTE* secdata;
  261.     
  262.     if (drive_writeprotected(drv)) return;
  263.     mend -= (4 + 16 + 8 + 512);
  264.     while (mbuf < mend) {
  265.     do {
  266.         while (*mbuf++ != 0x4489) {
  267.         if (mbuf >= mend) return;
  268.         }
  269.     } while (*mbuf++ != 0x4489);
  270.     
  271.     odd = getmfmlong(mbuf);
  272.     even = getmfmlong(mbuf+2);
  273.     mbuf += 4;    
  274.     id = (odd << 1) | even;
  275.     
  276.     drv->trackoffs = (id & 0xff00) >> 8;
  277.     if (drv->trackoffs > 10) {
  278.         printf("Disk write: weird sector number %d\n", drv->trackoffs);
  279.         continue;
  280.     }
  281.     chksum = odd ^ even;
  282.     for (i=0; i<4; i++) {
  283.         odd = getmfmlong(mbuf);
  284.         even = getmfmlong(mbuf+8);
  285.         mbuf += 2;
  286.         
  287.         dlong = (odd << 1) | even;
  288.         if (dlong)  secwritten = -200;
  289.         chksum ^= odd ^ even;
  290.     }  /* could check here if the label is nonstandard */
  291.     mbuf += 8;
  292.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  293.     if ((((odd << 1) | even) != chksum) || 
  294.         (((id & 0x00ff0000) >> 16) != drv->track*2 + side)) {
  295.         printf("Disk write: checksum error on sector header\n");
  296.         continue;
  297.     }
  298.     odd = getmfmlong(mbuf); even = getmfmlong(mbuf+2); mbuf += 4;
  299.     chksum = (odd << 1) | even;
  300.     secdata = drv->secbuf + 32;
  301.     for (i=0; i<128; i++) {
  302.         odd = getmfmlong(mbuf); even = getmfmlong(mbuf+256); mbuf += 2;
  303.         dlong = (odd << 1) | even;
  304.         *secdata++ = dlong >> 24; *secdata++ = (dlong >> 16) & 0xff;
  305.         *secdata++ = dlong >> 8; *secdata++ = dlong;
  306.         chksum ^= odd ^ even;
  307.     }
  308.     mbuf += 256;
  309.     if (chksum) {
  310.         printf("Disk write: data checksum error\n");
  311.         continue;
  312.     }
  313.     secwritten++;
  314.     fseek(drv->diskfile, 
  315.           drv->trackdata[drv->track*2 + side].offs + drv->trackoffs*512,
  316.           SEEK_SET);
  317.     fwrite(drv->secbuf+32, sizeof(UBYTE), 512, drv->diskfile);
  318.     }
  319.     if (++drv->trackoffs == 11) drv->trackoffs = 0;
  320.     drv->insecpos = 0;
  321.     drv->secok = 0;
  322.     
  323.     if (secwritten == 0) 
  324.     printf("Disk write in unsupported format\n");
  325.     if (secwritten < 0)
  326.     printf("Disk write: sector labels ignored\n");
  327. }
  328.  
  329.  
  330. static void drive_eject(drive *drv)
  331. {
  332.     if (!drive_empty(drv)) fclose(drv->diskfile);
  333.     drv->diskfile = 0;
  334. }
  335.  
  336. /* We use this function if we have no Kickstart ROM. */
  337. void DISK_ersatz_read (int tr, int sec, CPTR dest)
  338. {
  339.     int i;
  340.  
  341.     floppy[0].trackoffs = sec;
  342.     floppy[0].insecpos = 0;
  343.     
  344.     side = tr & 1;
  345.     floppy[0].track = tr >> 1;
  346.     drive_readsec(floppy);
  347.     for (i = 0; i < 512; i++) {
  348.     put_byte (dest + i, floppy[0].secbuf[32+i]);
  349.     }
  350.     
  351. }
  352.  
  353. void disk_eject(int num)
  354. {
  355.     gui_filename(num, "");
  356.     drive_eject(floppy + num);
  357. }
  358.  
  359. void disk_insert(int num, char *name)
  360. {
  361.     /* just to be sure */
  362.     drive_eject(floppy + num);
  363.     drive_insert(floppy + num, num, name);
  364. }
  365.  
  366. int disk_empty(int num)
  367. {
  368.     return drive_empty(floppy + num);
  369. }
  370.  
  371. void DISK_init()
  372. {
  373.     drive_insert(floppy, 0, df0);
  374.     if (disk_empty(0))
  375.     fprintf(stderr, "No floppy in drive 0.\n");
  376.     drive_insert(floppy + 1, 1, df1);
  377.     drive_insert(floppy + 2, 2, df2);
  378.     drive_insert(floppy + 3, 3, df3);
  379. }
  380.  
  381. void DISK_Index()
  382. {
  383.     int i;
  384.     for(i=0; i<4; i++) {    
  385.     drive_index(floppy + i);
  386.     }
  387. }
  388.  
  389. static int ledstate[] = { 0,0,0,0 };
  390.  
  391. void DISK_select(UBYTE data)
  392. {
  393.     int step_pulse;
  394.     int dr;
  395.     
  396.     if (selected != ((data >> 3) & 15)) 
  397.     dskready = 0;
  398.     selected = (data >> 3) & 15;
  399.     if (side != 1 - ((data >> 2) & 1)) {
  400.     side = 1 - ((data >> 2) & 1);
  401.     need_read = 1;
  402.     }
  403.     direction = (data >> 1) & 1;
  404.     step_pulse = data & 1;
  405.     if (step != step_pulse) {
  406.     step = step_pulse;
  407.     if (step == 0){
  408.         for (dr = 0; dr < 4; dr++){
  409.         if (!(selected & (1 << dr))) {
  410.             drive_step(floppy + dr);
  411.         }
  412.         }
  413.     }
  414.     }
  415.     for (dr = 0; dr < 4; dr++){
  416.     if (!(selected & (1<<dr))) {
  417.         drive_motor(floppy + dr, data >> 7);
  418.     }
  419.     }
  420.     for (dr = 0; dr < 4; dr++) {
  421.     int state = (!(selected & (1<<dr))) | !floppy[dr].motoroff;
  422.     if (state != ledstate[dr])
  423.         gui_led (dr+1, state);
  424.     ledstate[dr] = state;
  425.     }
  426. }
  427.  
  428. UBYTE DISK_status()
  429. {
  430.     UBYTE st = 0x3c;
  431.     int dr;
  432.     
  433.     for (dr = 0; dr < 4; dr++){
  434.     if (!(selected & (1 << dr))) {
  435.         if (drive_running(floppy + dr)){
  436.         if (dskready) st &= ~0x20;
  437.         dskready = 1;
  438.         } else {
  439.         st &= ~0x20; /* report drive ID */
  440.         }
  441.         
  442.         if (drive_track0(floppy + dr)) { st &= ~0x10; }
  443.         if (drive_writeprotected(floppy + dr)) { st &= ~8; }
  444.         if (drive_empty(floppy + dr)) { st &= ~0x4; }
  445.     }
  446.     }
  447.     return st;
  448. }
  449.  
  450. void DISK_GetData(UWORD *mfm,UWORD *byt)
  451. {
  452.     int dr;
  453.     for (dr = 0; dr < 4; dr++){
  454.     if (!(selected & (1<<dr))) {
  455.         drive_get_data (floppy + dr, mfm, byt);
  456.     }
  457.     }
  458. }
  459.  
  460. void DISK_InitWrite()
  461. {
  462.     mfmwrite = mfmwrbuffer;
  463. }
  464.  
  465. void DISK_WriteData()
  466. {
  467.     int dr;
  468.     for (dr=0;dr<4;dr++){
  469.     if (!(selected & (1<<dr))) {
  470.         drive_write_data(floppy + dr, mfmwrbuffer, mfmwrite);
  471.     }
  472.     }
  473. }
  474.